package org.appfuse.dao;

/**
 * 
 * @author <a href="mailto: baiyibing@gmail.com">王锤</a>
 * @version $Revision$
 * 
 */

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import ognl.Ognl;
import ognl.OgnlException;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.CompareToBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class RawEnhancedHql implements Comparable, Serializable {
	protected final Log log = LogFactory.getLog(getClass());
	private Set instances = new HashSet();

	public Set getInstances() {
		return instances;
	}

	public void setInstances(Set instances) {
		this.instances = instances;
	}

	private StringBuffer originalHql = new StringBuffer();

	public StringBuffer getOriginalHql() {
		return originalHql;
	}

	public void setOriginalHql(StringBuffer originalHql) {
		this.originalHql = originalHql;
	}
	
//	private Map toBeQueryMap = new HashMap();
//
//	public Map getToBeQueryMap() {
//		return toBeQueryMap;
//	}
//
//	public void setToBeQueryMap(Map toBeQueryMap) {
//		this.toBeQueryMap = toBeQueryMap;
//	}

	private Map addMap = new HashMap();

	public Map getAddMap() {
		return addMap;
	}

	public void setAddMap(Map addMap) {
		this.addMap = addMap;
	}

	public RawEnhancedHql append(RawEnhancedHql rehql) {
		this.getOriginalHql().append(rehql.getOriginalHql());
		this.getInstances().addAll(rehql.getInstances());
		this.getAddMap().putAll(rehql.getAddMap());
		//this.getToBeQueryMap().putAll(rehql.getToBeQueryMap());
		return this;
	}

	public EnhancedHql toEnhancedHql() {
		EnhancedHql enhancedHql = new EnhancedHql();
//		if (instances != null) {
//			for (Object instance : instances) {
//				if (instance != null) {
//					try {
//						this.describe(instance);
//					} catch (Exception e) {
//						// TODO Auto-generated catch block
//						log.debug("opHql BeanUtils.describe 出错");
//						e.printStackTrace();
//					}
//				}
//			}
//		}
		// String hql
		// ="select count(*) from ReportInstance as r where 1=1	and r.soInstance.guid in( select soInstanceGuid from UserSO as uso where uso.user.guid=:user.guid and uso.user.guid=:x.y)";
		String hqlchgto = originalHql.toString();
		Set set = new HashSet();
		Pattern pattern = Pattern.compile(".\\:{1}([\\w\\.\\-]+)[\\W\\)\\s$]{1}");
		Matcher matcher = pattern.matcher(originalHql + " ");
		ArrayList paramName = new ArrayList();
		while (matcher.find()) {
			log.debug("matcher.groupCount()=" + matcher.groupCount());
			for (int i = 1; i <= matcher.groupCount(); i++) {
				log.debug("matcher.group(" + i + ")=" + matcher.group(i));
				paramName.add(matcher.group(i));
				set.add(matcher.group(i));
				hqlchgto = StringUtils.replace(hqlchgto,
						":" + matcher.group(i), ":"
								+ StringUtils.replace(matcher.group(i), ".",
										"_"));
			}
		}
		log.debug("hqlchgto=" + hqlchgto);
		Map paramMap = new HashMap();
		String[] paramNames = (String[]) set.toArray(new String[0]);
		Object[] values = new Object[paramNames.length];
		for (int i = 0; i < paramNames.length; i++) {
			Object obj = addMap.get(paramNames[i]);
			if (obj == null) {
				if (instances != null) {
					for (Object instance : instances) {
						if (instance != null) {
							try {
								obj = Ognl.getValue(paramNames[i], instance);
							} catch (OgnlException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
							if (obj != null) {
								break;
							}
						}
					}
				}
			}
			values[i] = obj;
			paramNames[i] = StringUtils.replace(paramNames[i], ".", "_");
			log.debug(paramNames[i]);
			log.debug(values[i].toString());
			paramMap.put(paramNames[i], obj);
		}
		enhancedHql.setParamNames(paramNames);
		enhancedHql.setValues(values);
		enhancedHql.setHql(hqlchgto);
		enhancedHql.setParamSet(set);
		enhancedHql.setParamMap(paramMap);
		return enhancedHql;
	}

	public void describe(Object instance) throws Exception {
		Map map = BeanUtils.describe(instance);
		String[] paramNames = (String[]) map.keySet().toArray(new String[0]);
		for (int i = 0; i < paramNames.length; i++) {
			Object obj = map.get(paramNames[i]);
			log.debug(paramNames[i] + "=" + obj);
		}
	}

	// rehql.setAddMap(rehql.instances2AddMap(hql, reportInstance));
	public Map instances2AddMap(StringBuffer originalHql, Object... instances) {
		Map addMap = new HashMap();
		if (instances != null) {
			for (Object instance : instances) {
				if (instance != null) {
					try {
						this.describe(instance);
					} catch (Exception e) {
						// TODO Auto-generated catch block
						log.debug("opHql BeanUtils.describe 出错");
						e.printStackTrace();
					}
				}
			}
		}
		String hqlchgto = originalHql.toString();
		Set set = new HashSet();
		Pattern pattern = Pattern.compile(".\\:{1}([\\w\\.\\-]+)[\\W\\)\\s$]{1}");
		Matcher matcher = pattern.matcher(originalHql + " ");
		ArrayList paramName = new ArrayList();
		while (matcher.find()) {
			log.debug("matcher.groupCount()=" + matcher.groupCount());
			for (int i = 1; i <= matcher.groupCount(); i++) {
				log.debug("matcher.group(" + i + ")=" + matcher.group(i));
				paramName.add(matcher.group(i));
				set.add(matcher.group(i));
				hqlchgto = StringUtils.replace(hqlchgto,
						":" + matcher.group(i), ":"
								+ StringUtils.replace(matcher.group(i), ".",
										"_"));
			}
		}
		log.debug("hqlchgto=" + hqlchgto);
		String[] paramNames = (String[]) set.toArray(new String[0]);
		for (int i = 0; i < paramNames.length; i++) {
			Object obj = null;
			if (instances != null) {
				for (Object instance : instances) {
					if (instance != null) {
						try {
							obj = Ognl.getValue(paramNames[i], instance);
						} catch (OgnlException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						if (obj != null) {
							break;
						}
					}
				}
			}
			addMap.put(paramNames[i], obj);
		}
		return addMap;
	}

	/**
	 * @see java.lang.Comparable#compareTo(Object)
	 */
	public int compareTo(Object object) {
		RawEnhancedHql myClass = (RawEnhancedHql) object;
		return new CompareToBuilder().append(this.originalHql,
				myClass.originalHql).append(this.addMap, myClass.addMap)
				.toComparison();
	}
}
